#include <stdio.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <fcntl.h>
#include <assert.h>
#include <errno.h>
#include <client_async.h>
#include <poll_thread.h>
#include <log.h>
#include "dirty.h"


using namespace std;

#define MAX_HEADER_LEN		4 * 1024

//#define KEEPALIVE

CClientAsync::CClientAsync(CPollThread *o, int fd)
{
	owner = o;
	netfd = fd;
	
	stat = INIT;
	offset = 0;	

	m_bufferlen = 16 * 1024;
	recvbuf = new char[m_bufferlen];
	m_pbeg = m_pend = recvbuf;
	m_content_len = 0;

}

int CClientAsync::Attach()
{

	AttachTimer(owner->GetTimerList(5));
	EnableInput();
	return AttachPoller(owner);
}

CClientAsync::~CClientAsync ()
{    
	delete recvbuf;
}


void CClientAsync::InputNotify (void)
{

	char sMsg[255]={0};
	int32_t len = Recv();

	if(len <= 0)
	{
		sprintf(sMsg,"Init recv failed:%d,%s",offset,strerror(errno));
		ErrorProcess(sMsg);
		return;
	}
	
	if(stat == INIT)
	{
		InitProcess(len);
	}
	else if(stat == RECVING)
	{

		RecvingProcess(len);
	}
	else if(stat == RECVDONE)
	{
		RecvDoneProcess();
	}

	log_debug("out %s", __FUNCTION__);
	
}

void CClientAsync::OutputNotify (void)
{
	if(stat == SENDING)
	{
		SendingProcess();
		return;
	}
	else if(stat == DONE || stat == SENDDONE)
	{
		DoneProcess();
	}
}

void CClientAsync::TimerNotify(void)
{
	log_debug("session time out fd = %d", netfd);
	//delete this;
}

int32_t CClientAsync::Recv()
{
 	int32_t len = recv(netfd,m_pend, m_bufferlen - (m_pend - m_pbeg), 0);
	if(len > 0)
	{
		m_pend += len;
		time(&m_lasttime);
	}

	return len;

}


void CClientAsync::InitProcess(int32_t len)
{
	
	char tmp = *(m_pbeg + 4096);
	*(m_pbeg + 4096) = 0;
	*(m_pend + 1) = 0;
	char *pos;

	pos = strstr(m_pbeg, "\r\n\r\n") ;
	if(pos == NULL)
	{
		pos = strstr(m_pbeg, "\n\n") ;		//dos mod
		if(pos == NULL)
		{
			*(m_pbeg + 4096) = tmp;
			return;
		}

		*pos = 0;
		pos += 2;
	}
	else
	{
		*pos = 0;
		pos += 4;
	}

	stringstream ssHeaders;
	ssHeaders.str(m_pbeg);

	string key,value;

	key = "method";
	ssHeaders >> value;
	m_headers[key] = value;
	
	key = "uri";
	ssHeaders >> value;
	m_headers[key] = value;
	
	key = "proctol";
	ssHeaders >> value;
	m_headers[key] = value;

	string line;
	while(getline(ssHeaders,line))
	{
		string::size_type pos = line.find(": ");
		if(pos == string::npos) continue;
		
		key = line.substr(0, pos);
		value = line.substr(pos+2);
		m_headers[key] = value;
	}

	if(m_headers["method"] != "POST"  )
	{
		ErrorProcess("support POST only");
		return;
	}

	string slen = m_headers["Content-Length"];
	m_content_len = atoi(slen.c_str());

	if(m_content_len <= 0)
	{
		ErrorProcess("Bad content length");
		log_error("content-length: %d", m_content_len);
		return;
	}

	*(m_pbeg + 4096) = tmp;

	int left = m_pend - pos;
	if(m_content_len <= left)
	{
		m_body.append(pos, m_content_len);
		m_pend = m_pbeg + left - m_content_len;

		if(m_content_len != left)
		{
			memmove(m_pbeg, pos + m_content_len ,  left - m_content_len);
		}

		RecvDoneProcess();
		return;
		
	}
	else
	{
		m_body = pos;
		m_pend = m_pbeg;
		stat = RECVING;
	}

	//RecvCheck();

}




void CClientAsync::RecvingProcess(int32_t len)
{
	//char sMsg[255]={0};

	int need = m_content_len - m_body.size();
	if(need > len)
	{
		m_body.append(m_pbeg + offset, len);
		m_pend = m_pbeg;
		return;
	}

	m_body.append(m_pbeg+offset, need);

#if 0	//for keep alive
	if(need != len)
	{
		memmove(m_pbeg, m_pbeg + need,  len -need);
	}
#endif 

	m_pend = m_pbeg + len - need;

	stat = RECVDONE;
	
	RecvDoneProcess();
	
	//RecvCheck();
	
}


void CClientAsync::RecvDoneProcess()
{

	Dirty *pdirty = Dirty::getInstance();


	string uri = m_headers["uri"];
	if(uri.empty())
	return;
	
	log_info("uri: %s", uri.c_str());
	string::size_type pos = uri.find("/", 1);
	if(pos == string::npos)
	{
		return;
	}

	string serv = uri.substr(1, pos - 1);
	string src = uri.substr(pos + 1);
	
	pdirty->checkDirty(src, m_body.c_str(), m_body.size(), outbuf);
	stat = SENDING;
	DisableInput();
	EnableOutput();
	ApplyEvents();
}

void CClientAsync::SendingProcess()
{
	char sMsg[255] = {0};
	stringstream response;
	response << "HTTP/1.1 200 OK\r\n" ;
	response << "Content-Length: " << outbuf.str().size() << "\r\n";
	response  << "Content-Type: text/html\r\n\r\n";


	log_debug("%s", outbuf.str().c_str());
	
	int sendLen = send(netfd,response.str().c_str(), response.str().size(),0);
	if(sendLen == -1)
	{
		sprintf(sMsg,"send head failed:%s",strerror(errno));
		ErrorProcess(sMsg);
		return;
	}

	sendLen = send(netfd,outbuf.str().c_str(), outbuf.str().size(),0);
	if(sendLen == -1)
	{
		sprintf(sMsg,"send body failed:%s",strerror(errno));
		ErrorProcess(sMsg);
		return;
	}

	stat = SENDDONE;
	//DoneProcess();

}

void CClientAsync::DoneProcess()
{
	log_debug("DoneProcess:%d",netfd);
	DisableOutput();
	EnableInput();
	ApplyEvents();

#if 0		//for http keep alive proctol
	
	if(m_headers["Keepalive"] != "" )
	{

		if(m_pend != m_pbeg)
		InitProcess(m_pend - m_pbeg);
	}
	else
	{
		delete this;
	}

#else
	delete this;
#endif
	
}




void CClientAsync::RecvCheck()
{

	//check head;

}

void CClientAsync::ErrorProcess (const char* errMsg)
{
	log_error(errMsg);
	delete this;
}


